home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Education
/
World of Education.iso
/
world_r
/
romancvt.zip
/
ARAB2ROM.C
next >
Wrap
C/C++ Source or Header
|
1993-04-14
|
6KB
|
197 lines
/* arab2rom.c
David S McMeans Not copyrighted April 1993
mcmeans@dtedi.hq.aflc.af.mil
Arabic2Roman()
Converts an Arabic integer to its Roman equivalent.
Call
char *Arabic2Roman( num, buf )
unsigned long int num; integer to convert
char *buf; buffer in which conversion is returned
Returns
NULL if num is out of range 0 to 3,999,999.
POINTER otherwise
Description
The Romans had no concept of fractions, so all their numbers were integers.
At the time their system was created, one thousand was as large a number as
could be conceived and thus was given the letter M for magna (large). A
later modification extended the system a thousand fold. Any numeral with a
bar over it was defined as one thousand times its normal value. Since it is
not possible to write a character with an over-bar in ASCII, these numerals
are written with an underscore to their right ( M_ = 1000 * 1000 ).
I 1
V 5 V_ 5,000
X 10 X_ 10,000
L 50 L_ 50,000
C 100 C_ 100,000
D 500 D_ 500,000
M 1000 M_ 1,000,000
When a number has multiple forms, it's canonical form is the shorter. Nine
is written IX, not VIIII, and ninety is XC, not LXXXX. But, a numeral is
not allowed to modify another that is more than one maginitude greater.
The correct representation of 1990 is not MXM (1000 + 1000-10). Rather, it
is MCMXC (1000 + 1000-100 + 100-10). When writing 1990, you first write
the representation for 1000, then for 900, and then for 90. You do not write
down the numerals for 1000 and then for 990. The technique is to integrally
divide the number by its greatest magnitude and write down the Roman
representation for each result. For 1989, the greatest magnitude is 1000.
You would write down M. Divide by 1000, and the result is 989. Here the
largest magnitude is 900. Write down CM (1000-100). Strip off the 900, and
get 89. Now the greatest magnitude is 80. Write down LXXX. This leaves 9
which would be written as IX.
This system follows a peculiar pattern of addtion and subraction to generate
the values one through 10. Smaller numerals to the left of a larger are
subracted from the larger, and smaller numerals placed to the right are added.
1 I 11 XI 40 XL
2 II 12 XII
3 III 13 XIII 50 L
4 IV 14 IVX
5 V 15 XV 90 XC
6 VI 16 XVI
7 VII 17 XVII 100 C
8 VIII 18 XVIII
9 IX 19 XIX
10 X 20 XX
Note that 8, VIII, could be written more succinctly IIX (10-2). I expect,
only one numeral may be placed in a subtraction position.
The following constant strings are redefinable by the user. This allows one
to substitute different characters for over-bar numerals.
Roman_1 = "i"; Roman_5000 = "v_";
Roman_5 = "v"; Roman_10000 = "x_";
Roman_10 = "x"; Roman_50000 = "l_";
Roman_50 = "l"; Roman_100000 = "c_";
Roman_100 = "c"; Roman_500000 = "d_";
Roman_500 = "d"; Roman_1000000 = "m_";
Roman_1000 = "m";
To represent numbers four million and greater, a numeral for five million is
needed. Since no numerals exist above one million (though they could easily
be fabricated), Arabic2Roman() converts integers only in the range 0 to
3,999,999.
Notes
This was compiled from a discussion in comp.lang.pascal around March 1993.
Acknowledgements go to John J Cupak Jr, CPP (cupak@rapnet.sanders.lockheed.com),
Paul Robinson (tdarcos@access.digex.com), and
David Conrad (dave@tygra.michigan.com) for their informative articles,
Prof Timo Salmi (ts@uwasa.fi) for steering me in the direction of the
discussion, and to Arlin B Collins (bcollins@utdallas.edu) for sending me his
collection of the articles from the discussion.
Arabic2Roman() is a modified version of the Turbo Pascal function Roman in
tools.pas which is in garbo.uwasa.fi:/pc/turbopas/drcpas10.zip
*/
#include "tailor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ulong unsigned long int
/* The following constants determine the representation of each Roman
numeral, and may be redefined by the user
*/
char *Roman_1 = "i";
char *Roman_5 = "v";
char *Roman_10 = "x";
char *Roman_50 = "l";
char *Roman_100 = "c";
char *Roman_500 = "d";
char *Roman_1000 = "m";
char *Roman_5000 = "v_";
char *Roman_10000 = "x_";
char *Roman_50000 = "l_";
char *Roman_100000 = "c_";
char *Roman_500000 = "d_";
char *Roman_1000000 = "m_";
/*
* PUBLIC DECLARATIONS
*/
extern char *Arabic2Roman OF(( ulong, char * ));
/*
* PRIVATE DECLARATIONS
*/
static void roman_digit OF(( char *, char *, char *, ulong, char * ));
char *Arabic2Roman( num, buf )
ulong num;
char *buf;
{
strcpy( buf, "" );
if (num > 3999999)
return NULL;
roman_digit( Roman_1000000, " ", " ", num/1000000, buf );
num %= 1000000;
roman_digit( Roman_100000, Roman_500000, Roman_1000000, num/100000, buf );
num %= 100000;
roman_digit( Roman_10000, Roman_50000, Roman_100000, num/10000, buf );
num %= 10000;
roman_digit( Roman_1000, Roman_5000, Roman_10000, num/1000, buf );
num %= 1000;
roman_digit( Roman_100, Roman_500, Roman_1000, num/100, buf );
num %= 100;
roman_digit( Roman_10, Roman_50, Roman_100, num/10, buf );
num %= 10;
roman_digit( Roman_1, Roman_5, Roman_10, num, buf );
return buf;
}
static void roman_digit( one, five, ten, n, buf )
char *one, *five, *ten;
ulong n;
char *buf;
{
int i;
switch( n )
{
case 1: case 2: case 3:
for (i=0; i < n; i++)
strcat( buf, one );
break;
case 4:
strcat( buf, one );
strcat( buf, five );
break;
case 5: case 6: case 7: case 8:
strcat( buf, five );
for (i=0; i < n-5; i++)
strcat( buf, one );
break;
case 9:
strcat( buf, one );
strcat( buf, ten );
break;
}
}
/* end .c */